import { EventEmitter, Injectable } from '@angular/core';
import { GraphBase } from './GraphBase';
import { GraphConfigService, OptionSetting, PluginSetting } from './graph-config.service';
import { Graph } from '@antv/x6';
import { ScenarioMetaService } from './scenario-meta.service';
import { Dnd } from '@antv/x6-plugin-dnd';
import { CellType } from '../enums';
import { CellConfig, PiplineConifg, ScenarioConfig, SiteNodeConfig, SrmConfig } from '../models';

@Injectable()
export class DesignGraphUtilService extends GraphBase {
  cellselected: EventEmitter<CellConfig> = new EventEmitter();
  scenario!: ScenarioConfig;

  constructor(service: GraphConfigService,
    private metaService: ScenarioMetaService
  ) {
    super(service);
  }

  protected override initGraph(): void {
    this.graph = new Graph({
      ...this.service.getGraphOptions(this._getOptionSetting()),
      autoResize: this.container,
      container: this.container,
    });
  }

  private _getOptionSetting(): Partial<OptionSetting> {
    return {
      background: true,
      grid: true,
      panning: true,
      mousewheel: true,
      embedding: true,
      highlighting: true,
    };
  }

  protected override registers(): void {
  }
  protected override getPluginSetting(): Partial<PluginSetting> {
    return {
      selecton: true,
      transform: true,
      keyboard: true,
    };
  }
  protected override bindKeys(): void {
    const { graph } = this;
    // #region 快捷键与事件
    graph.bindKey(['meta+c', 'ctrl+c'], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.copy(cells);
      }
      return false;
    });
    graph.bindKey(['meta+x', 'ctrl+x'], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.cut(cells);
      }
      return false;
    });
    graph.bindKey(['meta+v', 'ctrl+v'], () => {
      if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 });
        graph.cleanSelection();
        graph.select(cells);
      }
      return false;
    });

    // undo redo
    graph.bindKey(['meta+z', 'ctrl+z'], () => {
      if (graph.canUndo()) {
        graph.undo();
      }
      return false;
    });
    graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
      if (graph.canRedo()) {
        graph.redo();
      }
      return false;
    });

    // select all
    graph.bindKey(['meta+a', 'ctrl+a'], () => {
      const nodes = graph.getNodes();
      if (nodes) {
        graph.select(nodes);
      }
    });

    // delete
    graph.bindKey(['delete'], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.removeCells(cells);
      }
    });

    graph.on("node:click", ({ node }) => {
      // const cfg = this._getCellConfig(node);
      // if (cfg) {
      //   cfg.Type = node.data.category;
      //   this.cellselected.emit(cfg);
      // }
    });
    graph.on("node:unselected", ({ node }) => {
      this.cellselected.emit(undefined);
    });

    graph.on("node:dblclick", ({ node }) => {

      const cfg = this.metaService.getCellConfig(node);
      if (cfg) {
        cfg.Type = node.data.category;
        this.cellselected.emit(cfg);
      }
    });

    graph.on('node:change:parent', ({ node }) => {
      const parent = node.getParent();
      if (parent) {
        node.zIndex = parent.zIndex! + 1;
      }
    });

    graph.on("node:added", () => {
      this.getScenario();
    }).on("node:changed", () => {
      this.getScenario();
    }).on("node:removed", () => {
      this.getScenario();
    });
  }

  initDnd(container: HTMLElement) {
    return new Dnd({
      target: this.graph,
      scaled: false,
      dndContainer: container,
    });
  }

  updateScenarioNode(item: CellConfig) {
    switch (item.Type) {
      case CellType.Pipline:
        {
          const pipline = item as PiplineConifg;
          this.scenario.Lines = this.scenario.Lines.map(a => a.Id == item.Id ? { ...pipline, Sites: a.Sites } : a);
        }
        break;
      case CellType.Site:
        {
          const site = item as SiteNodeConfig;
          if (site.ParentId) {
            const line = this.scenario.Lines.find(a => a.Id == site.ParentId);
            if (line) {
              line.Sites = line.Sites.map(a => a.Id == site.Id ? site : a);
            }
          }
        }
        break;
      case CellType.Srm:
        {
          const srm = item as SrmConfig;
          this.scenario.Srms = this.scenario.Srms.map(a => a.Id == srm.Id ? srm : a);
        }
    }
    this.metaService.loadScenario(this.graph, this.scenario);
  }
  getScenario(): ScenarioConfig {
    this.scenario = this.metaService.getScenario(this.graph.getNodes(), this.scenario);
    return this.scenario;
  }
  loadScenario(cfg: ScenarioConfig) {
    this.scenario = cfg;
    this.metaService.loadScenario(this.graph, cfg);
  }
}